package com.realife.eson.common.result;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.realife.eson.common.asserts.AssertNP;
import com.realife.eson.common.enums.ResponseEnum;
import lombok.Data;
import lombok.ToString;
import org.joda.time.DateTime;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

@ToString
@Data
public class R<E> implements Serializable {
    private static final long serialVersionUID = 1L;

    private Boolean success;
    private Integer code;
    private String message;
    private String timestamp; //时间
    private Map<String, Object> data = new HashMap<>();
    private E result;

    /**
     * 构造函数私有化
     */
    private R() {
    }


    /**
     * @param content
     * @param typeReference
     * @param <T>
     * @return
     */
    public static <T> T getResultData(String content, TypeReference<T> typeReference) {
        R r = JSON.parseObject(content, R.class);
        Object result = r.getResult();
        String resultJson = JSON.toJSONString(result);
        T t = JSON.parseObject(resultJson, typeReference);
        return t;
    }


    /**
     *
     * @param content 内容
     * @param typeReference 引用类型
     * @param <T> 目标类型
     * @return
     */
    public static <T> T getTargetObj(String content, TypeReference<T> typeReference) {
        return JSON.parseObject(content, typeReference);
    }


    /**
     * 逆转出自己想要的后端对象
     */
    public <T> T getAnyData(String key, TypeReference<T> typeReference) {
        Map<String, Object> map = getData();
        Object data = map.get(key);
        String s = JSON.toJSONString(data);
        T t = JSON.parseObject(s, typeReference);
        return t;
    }

    /**
     * 逆转出自己想要的后端对象
     */
    public static <T> T getAllData(String responseStr, TypeReference<T> typeReference) {
        R r = JSON.parseObject(responseStr, R.class);
        Map<String, Object> map = r.getData();
        //
        Set<String> keys = map.keySet();
        if (AssertNP.allTrue(AssertNP.legalParams(keys)) && keys.size() == 1) {
            for (String key : keys) {
                Object data = map.get(key);
                String s = JSON.toJSONString(data);
                T t = JSON.parseObject(s, typeReference);
                return t;
            }
        }
        return null;
    }


    /**
     * 可能什么都没有
     *
     * @param content
     * @return
     */
    public static R getR(String content) {
        return JSON.parseObject(content, R.class);
    }


    public static <E> R<E> ok(E e) {
        R<E> r = new R<>();
        r.setSuccess(true);
        r.setCode(ResponseEnum.SUCCESS.getStatusCode());
        r.setMessage(ResponseEnum.SUCCESS.getMessage());
        r.setTimestamp(DateTime.now().toString("yyyy-MM-dd HH:mm:ss"));
        r.setResult(e);
        return r;
    }


    /**
     * 返回成功结果
     *
     * @return
     */
    public static R ok() {
        R r = new R();
        r.setSuccess(true);
        r.setCode(ResponseEnum.SUCCESS.getStatusCode());
        r.setMessage(ResponseEnum.SUCCESS.getMessage());
        r.setTimestamp(DateTime.now().toString("yyyy-MM-dd HH:mm:ss"));
        return r;
    }

    /**
     * 返回失败结果
     *
     * @return
     */
    public static R error() {
        R r = new R();
        r.setSuccess(false);
        r.setCode(ResponseEnum.ERROR.getStatusCode());
        r.setMessage(ResponseEnum.ERROR.getMessage());
        r.setTimestamp(DateTime.now().toString("yyyy-MM-dd HH:mm:ss"));
        return r;
    }


    public static <E> R<E> tips(E e) {
        R<E> r = new R<>();
        r.setSuccess(false);
        r.setCode(ResponseEnum.ERROR.getStatusCode());
        r.setMessage(ResponseEnum.ERROR.getMessage());
        r.setTimestamp(DateTime.now().toString("yyyy-MM-dd HH:mm:ss"));
        r.setResult(e);
        return r;
    }


    /**
     * 返回失败结果
     *
     * @return
     */
    public static R fail(ResponseEnum responseEnum) {
        R r = new R();
        r.setSuccess(false);
        r.setCode(responseEnum.getStatusCode());
        r.setMessage(responseEnum.getMessage());
        r.setTimestamp(DateTime.now().toString("yyyy-MM-dd HH:mm:ss"));
        return r;
    }


    /**
     * 设置特定的结果
     *
     * @param responseEnum
     * @return
     */
    public static R setResult(ResponseEnum responseEnum, boolean success) {
        R r = new R();
        r.setSuccess(success);
        r.setCode(responseEnum.getStatusCode());
        r.setMessage(responseEnum.getMessage());
        r.setTimestamp(DateTime.now().toString("yyyy-MM-dd HH:mm:ss"));
        return r;
    }


    /**
     * 统一异常处理使用
     *
     * @param success
     * @param code
     * @param message
     * @return
     */
    public static R setResult(boolean success, Integer code, String message) {
        R r = new R();
        r.setSuccess(success);
        r.setCode(code);
        r.setMessage(message);
        r.setTimestamp(DateTime.now().toString("yyyy-MM-dd HH:mm:ss"));
        return r;
    }

    /**
     * 统一异常处理使用
     *
     * @param success
     * @param message
     * @return
     */
    public static R setException(boolean success, String message) {
        R r = new R();
        r.setSuccess(success);
        r.setCode(ResponseEnum.EXCEPTION_EXC.getStatusCode());
        r.setMessage(message);
        r.setTimestamp(DateTime.now().toString("yyyy-MM-dd HH:mm:ss"));
        return r;
    }

    /**
     * 统一异常处理使用
     *
     * @param success
     * @param message
     * @return
     */
    public static R setThrowable(boolean success, String message) {
        R r = new R();
        r.setSuccess(success);
        r.setCode(ResponseEnum.THROWABLE_ERR.getStatusCode());
        r.setMessage(message);
        r.setTimestamp(DateTime.now().toString("yyyy-MM-dd HH:mm:ss"));
        return r;
    }

    /**
     * 统一异常处理使用
     *
     * @param success
     * @param message
     * @return
     */
    public static R setBeforeWeb(boolean success, String message) {
        R r = new R();
        r.setSuccess(success);
        r.setCode(ResponseEnum.SERVLET_ERROR.getStatusCode());
        r.setMessage(ResponseEnum.SERVLET_ERROR.getMessage() + " >> " + message);
        r.setTimestamp(DateTime.now().toString("yyyy-MM-dd HH:mm:ss"));
        return r;
    }


    public R data(String key, Object value) {
        this.data.put(key, value);
        return this;
    }


    public R data(Map<String, Object> map) {
        this.setData(map);
        return this;
    }

    /**
     * 设置特定的响应消息
     *
     * @param message
     * @return
     */
    public R message(String message) {
        this.setMessage(message);
        return this;
    }


    /**
     * 设置特定的响应码
     *
     * @param code
     * @return
     */
    public R code(Integer code) {
        this.setCode(code);
        return this;
    }
}
